本日核心價值 (Core Focus): 把「能在新機器跑起來」拆成可複用 Prompt 模組:
docker-compose(api + postgres)、不含密鑰的.env.example、Makefile、.editorconfig、本地 README,以及給 Codex 看的AGENTS.md測試指令;Windows 另外處理換行與 WSL。
概念說明與實戰情境 (Overview)
新專案最耗時間的往往不是第一個 API,而是每個人的本機環境不一致:有人裝原生 PostgreSQL,有人用 Docker,有人把真實密碼寫進 .env 再誤提交。把環境搭建丟給一次超長 Prompt,模型容易漏健康檢查、把 secret 寫進 compose、或產出只在 Linux 能跑的 Makefile。改成模組庫之後,每個模組只負責一種產物,輸入是埠號、服務名與「禁止出現真實密鑰」;輸出必須是可複製檔案。Codex 則靠 repo 根目錄 AGENTS.md 知道如何建置與跑測試,而不是每次重講。
關鍵操作與範例 (Implementation & Example)
模組庫建議固定五個產物,外加一份給 Agent 的操作說明。每個模組都有自己的 Prompt,不要併成「幫我初始化整個公司 infra」。建議執行順序也固定:先 env 與 compose(沒有變數名,YAML 只能把密碼寫死)、再 make / .editorconfig(讓啟動指令與換行穩定)、再 README Local 段、最後 AGENTS.md。後兩個模組必須「引用」前面已存在的檔名與指令,禁止再發明一套 start.sh。
驗收標準很具體:在空目錄套用這組輸出後,同事只做三件事就能跑測試——複製 .env.example、啟動 compose、執行測試指令。少任何一檔,或 api 在 postgres 尚未 ready 時就連線,都不算模組庫成功。
| 模組 | 必備輸出 | 硬性約束 |
|---|---|---|
compose |
docker-compose.yml |
api + postgres;postgres 要 healthcheck |
env |
.env.example |
只有變數名與假值,禁止真實 token |
make |
Makefile |
up / down / test / logs |
editor |
.editorconfig |
宣告 lf;C# / Python / YAML 縮排 |
readme |
README.md 的 Local 段 |
複製 .env.example、啟動、跑測 |
agents |
AGENTS.md |
寫清測試指令與 Sandbox 注意事項 |
共用系統 Prompt(每個模組都帶上):
你正在產出可提交的 repo 檔案,不是教學散文。
約束:
- 不要寫真實密碼、API key、連線字串中的 credential。
- 不要假設讀者已安裝特定雲 CLI。
- Windows 使用者可能用 Docker Desktop + WSL2;腳本換行必須是 LF。
- 每個檔案先給路徑,再給完整內容。
- 若缺少埠號或映像版本,使用可替換預設值並在註解標明。
compose 模組 Prompt:
產出 docker-compose.yml。
服務:api(build: .)、postgres(postgres:16-alpine)。
api 依賴 postgres healthy。
postgres 的 POSTGRES_* 全部來自 env_file,不要把密碼寫死在 YAML。
加上 healthcheck(pg_isready)與 named volume。
api 暴露 8080。不要加入 cloud vendor 特定網路外掛。
可直接使用的 docker-compose.yml:
services:
api:
build:
context: .
dockerfile: Dockerfile
ports:
- "8080:8080"
env_file:
- .env
environment:
ASPNETCORE_URLS: http://0.0.0.0:8080
ConnectionStrings__Default: Host=postgres;Port=5432;Database=${POSTGRES_DB};Username=${POSTGRES_USER};Password=${POSTGRES_PASSWORD}
depends_on:
postgres:
condition: service_healthy
restart: unless-stopped
postgres:
image: postgres:16-alpine
env_file:
- .env
ports:
- "5432:5432"
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
interval: 5s
timeout: 5s
retries: 10
restart: unless-stopped
volumes:
pgdata:
對應的 .env.example(可提交;真正的 .env 必須在 .gitignore):
# 複製為 .env 後再改值。禁止把真實密鑰提交進 git。
POSTGRES_USER=app
POSTGRES_PASSWORD=change_me_local_only
POSTGRES_DB=appdb
POSTGRES_PORT=5432
API_PORT=8080
ASPNETCORE_ENVIRONMENT=Development
# 若之後接 ChatGPT API,只放變數名,值留空給本機填
OPENAI_API_KEY=
連線字串有兩個常見陷阱,Prompt 必須寫死,否則本機與容器各成功一次、彼此連不上。容器內的 api 連 postgres 要用主機名 postgres(compose 服務名),開發者在 Windows 主機跑 dotnet test 則改連 localhost 與對應的 mapped port。.env.example 可以同時提供 POSTGRES_HOST=postgres 與註解說明「在主機跑測試時改成 localhost」,但不要讓模型產出兩套互相覆蓋的 compose。Volume 銷毀與 down 也要分開寫:日常停服務用 docker compose down,需要清空資料庫才加 -v;Prompt 若把兩者寫成同一指令,同事第一次練習就會丟掉本機資料。
Makefile 模組讓指令穩定,避免每人記一組不同的 docker compose 參數:
COMPOSE=docker compose
.PHONY: up down logs test env
env:
@test -f .env || cp .env.example .env
up: env
$(COMPOSE) up --build -d
down:
$(COMPOSE) down
logs:
$(COMPOSE) logs -f api
test:
$(COMPOSE) exec api dotnet test --nologo
.editorconfig 專門處理 Windows 與跨編輯器差異。未宣告 end_of_line 時,PowerShell 與 Git 常把 shell 腳本存成 CRLF,在 Linux 容器裡出現 $'\r': command not found。
root = true
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[*.{cs,csproj,json}]
indent_style = space
indent_size = 4
[*.{yml,yaml,py,md}]
indent_style = space
indent_size = 2
[Makefile]
indent_style = tab
建議一併提交 .gitattributes,把換行從「編輯器設定」提升成 git 契約,否則有人關掉 EditorConfig 外掛後,CRLF 仍會進 repo:
* text=auto eol=lf
*.cs text diff=csharp
*.sh text eol=lf
Makefile text eol=lf
沒有 make 的 Windows 原生環境,README 必須給等價命令,否則模組庫只服務一半同事:
copy .env.example .env
docker compose up --build -d
docker compose exec api dotnet test --nologo
docker compose logs -f api
docker compose down
把這些 Prompt 模組放進 repo 的 prompts/dev-env/(對應 Day 04 的指令庫),每個檔案只含一種產物的系統約束與輸入欄位:compose.md、env.md、make.md、editorconfig.md、readme-local.md、agents.md。之後開新服務時,只要填服務名、埠號、測試指令三個欄位再跑同一組模組,而不是重新描述公司慣例。模組變更走 PR,並抽一筆「空目錄套用後能否 compose up」當回歸,避免有人「優化 Prompt」後拿掉 healthcheck。
本地 README 只要能讓同事在 10 分鐘內達到綠燈,不要寫產品願景。最小段落:先決條件(Docker Desktop、可選 WSL2)、複製環境檔、make up 或上面的 docker compose、make test、如何看 postgres log、如何銷毀 volume。寫「先決條件」時點名 Docker Desktop 版本與「WSL2 backend 已開啟」,不要寫成「安裝一些工具」。README 也要寫失敗時先看哪裡:docker compose ps 是否 healthy、api log 是否還在等資料庫、.env 是否從 example 複製而來。這三行能省掉大半「我機器跑不起來」的來回。
Codex 不會自動知道「測試怎麼跑」,除非寫進 AGENTS.md。官方把 AGENTS.md 當成給 agent 的 README:repo 怎麼建、測試與 lint 指令、完成定義、以及不要做的事。根目錄放一份精簡檔,比在每次 Prompt 重複貼規則更穩。/init 可產生草稿,但必須改成團隊真實指令。
# AGENTS.md
## Layout
- `src/Api`:ASP.NET Core Web API
- `tests/Api.Tests`:xUnit
- `docker-compose.yml`:api + postgres
## How to run
- 複製 `.env.example` 為 `.env`(不要提交 `.env`)
- `make up` 啟動相依服務
- API 預設 `http://localhost:8080`
## Tests
- 優先跑受影響專案:`dotnet test tests/Api.Tests/Api.Tests.csproj --nologo`
- 需要資料庫的整合測試:先確認 postgres healthy,再跑 `make test`
- 不要對正式環境連線字串跑測試
## Conventions
- 密鑰只從環境變數讀取
- 變更 compose 或 migration 時,更新 `.env.example` 與 README Local 段
- Windows:在 WSL2 或確認 Git `core.autocrlf` 與 `.editorconfig` 使用 LF,再執行 shell 腳本
## Done means
- 測試通過
- `docker compose config` 可解析
- 沒有把真實密鑰寫進 diff
Windows 補充應寫進 README 與 AGENTS.md 同一段,避免只發生在某位使用者機器上。本機路徑建議放在 WSL 的 Linux 檔案系統(例如 ~/src),不要把 repo 放在 /mnt/c/... 再讓容器去掛載:跨檔案系統的 bind mount 會讓還原、檔案監看與測試變慢,也較容易出現權限與換行混用。Docker Desktop 的 WSL2 backend 開啟後,在 Ubuntu 終端執行 docker compose,與 Makefile 預設的 LF 腳本一致。
/mnt/c 穩定。core.autocrlf=input 搭配 .editorconfig 的 lf,不要讓 Makefile 變成 CRLF。make 若在原生 PowerShell 不可用,文件提供等價的 docker compose 命令,或引導改用 WSL。.env 與 compose 的 ports mapping,不要改容器內 listen port 除非應用一併改。dotnet test 換成 composer test 或 phpunit,並把對應指令寫進 AGENTS.md,不要另開一套「PHP 專用初始化神話」。把五個模組的輸出一次 PR 進 repo 後,之後新服務只要改服務名與埠號再跑同一組 Prompt,而不是重新描述「我們公司怎麼開專案」。Codex 讀到 AGENTS.md 的 Tests 段,才有辦法在 workspace-write Sandbox 裡自己跑 dotnet test,這也是 Day 16 Self-Correction Loop 能成立的前提:停止條件必須寫在 repo,不能寫在某次聊天。若測試需要 postgres,應在 AGENTS.md 寫「先確認 compose healthcheck 通過」,避免 agent 在資料庫未就緒時把紅燈當成程式錯誤而亂改碼。
注意事項與常見失敗 (Pitfalls)
docker-compose.yml 或範例檔: 這會進 git 歷史。修法:compose 只引用變數;提交 .env.example;.env 進 .gitignore;Prompt 明確禁止 credential。condition: service_healthy。修法:compose 模組把 healthcheck 當必填欄位。python\r 或 make\r。修法:.editorconfig + .gitattributes(* text=auto eol=lf)+ 在 WSL 執行。AGENTS.md 寫成論文: Codex 有 project_doc_max_bytes 上限,過長會被截斷。修法:只留 layout、run、test、done、do-not;細節連到 README。make: 純 Windows 原生環境可能沒有。修法:README 同時給 docker compose 原生命令。本日總結 (Takeaways)
docker-compose.yml 與 .env.example 必須可複製且不含真實密鑰。.editorconfig 先鎖 LF,再談 WSL 與 Docker Desktop。AGENTS.md 寫測試怎麼跑與何謂完成,Codex 才能在 Sandbox 裡自我驗證。明日預告 (Next)
明天收斂前 27 天最常踩的錯:避坑指南:打造 AI 工作流最常踩的 5 個坑點與解決方案。